﻿// /*******************************************************
//  * Copyright (C) RR-Bytes - All Rights Reserved
//  * Licence: MIT
//  * This file is part of the <Deploy Sources>
//  * Written by Ralf Röttcher, March 2017
// *******************************************************/
using DeploySources.Helper;
using DeploySources.MVVM;
using Microsoft.SharePoint.Client;
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Security;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using DeploySources.View;
using Microsoft.Win32;

namespace DeploySources.ViewModel
{
	/// <summary>
	/// ViewModel for the MainWindowView
	/// </summary>
	public class MainWindowViewModel : BaseViewModel
	{
		/// <summary>
		/// Constructor
		/// </summary>
		public MainWindowViewModel()
		{
			LoadConnections();
			ConnectedImage = GetImageSource(Properties.Resources.Red);
			IsConnected = false;
		}

		private ObservableCollection<ConnectionItem> _connections;

		/// <summary>
		/// Available connections to connect to
		/// </summary>
		public ObservableCollection<ConnectionItem> Connections
		{
			get
			{
				if (_connections == null)
				{
					_connections = new ObservableCollection<ConnectionItem>();
				}
				return _connections;
			}
			set
			{
				_connections = value;
				OnPropertyChanged("Connections");
			}
		}

		private ClientContext _context;

		private BaseViewModel _viewModel;
		/// <summary>
		/// ViewModel for the main content presenter
		/// </summary>
		public BaseViewModel ViewModel
		{
			get { return _viewModel; }
			set
			{
				_viewModel = value;
				OnPropertyChanged("ViewModel");
			}
		}

		private RelayCommand _manageConnectionsCommand;
		/// <summary>
		/// Menu command to mannage connections
		/// </summary>
		public RelayCommand ManageConnectionsCommand => _manageConnectionsCommand ?? (_manageConnectionsCommand = new RelayCommand(
			                                                param => ManageConnections()
		                                                ));

		/// <summary>
		/// Handle manage connections
		/// </summary>
		public void ManageConnections()
		{
			var manageConnections = new ManageConnectionsView
			{
				Owner = Application.Current.MainWindow,
				WindowStartupLocation = WindowStartupLocation.CenterOwner
			};
			var result = manageConnections.ShowDialog();

			if (result == true)
			{
				LoadConnections();
			}
		}

		private RelayCommand _closeApplicationCommand;
		/// <summary>
		/// Close application command
		/// </summary>
		public RelayCommand CloseApplicationCommand => _closeApplicationCommand ?? (_closeApplicationCommand = new RelayCommand(
			                                               param => CloseApplication()
		                                               ));

		/// <summary>
		/// Close the application method
		/// </summary>
		public void CloseApplication()
		{
			Application.Current.Shutdown();
		}

		private RelayCommand _aboutCommand;
		/// <summary>
		/// Call about command
		/// </summary>
		public RelayCommand AboutCommand => _aboutCommand ?? (_aboutCommand = new RelayCommand(
			                                    param => About()
		                                    ));

		/// <summary>
		/// Handle showing about box
		/// </summary>
		public void About()
		{
			var about = new AboutBox
			{
				Owner = Application.Current.MainWindow,
				WindowStartupLocation = WindowStartupLocation.CenterOwner
			};
			about.ShowDialog();
		}

		private ConnectionItem _connection;
		/// <summary>
		/// Current selected connection
		/// </summary>
		public ConnectionItem Connection
		{
			get { return _connection; }
			set
			{
				_connection = value ?? new ConnectionItem();

				OnPropertyChanged("Connection");
			}
		}
		
		private RelayCommand _connectionCommand;
		/// <summary>
		/// Connecto to SharePoint command
		/// </summary>
		public RelayCommand ConnectionCommand => _connectionCommand ?? (_connectionCommand = new RelayCommand(
			                                         param => Connect()
		                                         ));

		private RelayCommand _selectArtefactFileCommand;
		/// <summary>
		/// Select the Artefactfile
		/// </summary>
		public RelayCommand SelectArtefactFileCommand => _selectArtefactFileCommand ?? (_selectArtefactFileCommand = new RelayCommand(
															param => SelectArtefactFile()
														));

		private void SelectArtefactFile()
		{
			var openFileDialog = new OpenFileDialog();
			openFileDialog.DefaultExt = ".cs";
			openFileDialog.Filter = "CS Files (*.cs)|*.cs";


			if (openFileDialog.ShowDialog() == true)
				Connection.ArtefactFile = openFileDialog.FileName;
			OnPropertyChanged("Connection");
		}

		/// <summary>
		/// Handle connect to SharePoint
		/// </summary>
		private void Connect()
		{
			if (IsConnected)
			{
				if (_context != null)
				{
					_context.Dispose();
					_context = null;
				}
				
				IsConnected = false;
			}
			else
			{
				// Check out the following article if you have a Multi Factor Authentication active in your tenant
				// https://support.office.com/en-us/article/Set-up-multi-factor-authentication-for-Office-365-users-8f0454b2-f51a-4d9c-bcde-2c48e41621c6?ui=en-US&rs=en-US&ad=US
				_context = new ClientContext(Connection.Url);

				if (Connection.IsSharePointOnline)
				{
					_context.Credentials = new SharePointOnlineCredentials(Connection.Username, ConvertToSecureString(Connection.Password));
				}
				else
				{
					_context.Credentials = new NetworkCredential(Connection.Username, Connection.Password);
				}

				_context.Load(_context.Web, w => w.Title);

				try
				{
					_context.ExecuteQuery();
				}
				catch (Exception)
				{
					MessageBox.Show("Was not able to connect to SharePoint. Please check your connection parameters.", "Connection Error", MessageBoxButton.OK, MessageBoxImage.Error);
					IsConnected = false;
					return;
				}
				
				IsConnected = true;

				AddConnectionItem();
			}
		}

		/// <summary>
		/// Text for the connect / disconnect button
		/// </summary>
		public string ConnectionText => IsConnected ? "Disconnect" : "Connect";

		private bool _isConnected;
		/// <summary>
		/// Status of the SharePoint connection
		/// </summary>
		public bool IsConnected
		{
			get { return _isConnected; }
			set
			{
				_isConnected = value;
				Mediator.NotifyColleagues("IsConnected", new ConnectedParameter { IsConnected = _isConnected, Context = _context, Connection = Connection ?? new ConnectionItem() });
				ConnectedImage = GetImageSource(_isConnected ? Properties.Resources.Green : Properties.Resources.Red);
				OnPropertyChanged("IsConnected");
				OnPropertyChanged("ConnectionText");
			}
		}

		/// <summary>
		/// Load the stored connections
		/// </summary>
		private void LoadConnections()
		{
			Connections = new ObservableCollection<ConnectionItem>(ConnectionSerializer.Deserialize());

			if (Connections.Count == 0)
			{
				Connections.Add(new ConnectionItem());
			}

			if (Connections.Count > 0)
			{
				Connection = _connections.First();
			}
		}

		/// <summary>
		/// Add a manually entered connection to the available connections
		/// </summary>
		private void AddConnectionItem()
		{
			var con = Connection.Clone();

			var index = _connections.IndexOf(con);

			_connections.Insert(0, con);

			Connection = _connections.First();

			if (index != -1)
			{
				_connections.RemoveAt(index + 1);
			}

			ConnectionSerializer.Serialize(_connections.ToList());
		}

		private ImageSource _connectedImage;
		/// <summary>
		/// Image to show the status of the SharePoint connection
		/// </summary>
		public ImageSource ConnectedImage
		{
			get
			{
				return _connectedImage;
			}
			set
			{
				_connectedImage = value;
				OnPropertyChanged("ConnectedImage");
			}
		}

		/// <summary>
		/// Convert a Resource to be shown in an image
		/// </summary>
		/// <param name="bitmap">Resource to convert</param>
		/// <returns>Converted resource</returns>
		public ImageSource GetImageSource(System.Drawing.Bitmap bitmap)
		{
			var ms = new MemoryStream();
			bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
			var image = new BitmapImage();
			image.BeginInit();
			ms.Seek(0, SeekOrigin.Begin);
			image.StreamSource = ms;
			image.EndInit();

			return image;
		}
		
		/// <summary>
		/// Convert a string to secure string
		/// </summary>
		/// <param name="password">Password to be converted</param>
		/// <returns>Password as a secure string</returns>
		private SecureString ConvertToSecureString(string password)
		{
			if (password == null)
				throw new ArgumentNullException(nameof(password));
		
			var securePassword = new SecureString();
		
			foreach (char c in password)
				securePassword.AppendChar(c);
		
			securePassword.MakeReadOnly();
			return securePassword;
		}
	}
}
